package com.fizzkai.p2p.bussness.service.impl;

import com.fizzkai.p2p.bussness.domain.Bid;
import com.fizzkai.p2p.bussness.domain.BidRequest;
import com.fizzkai.p2p.bussness.domain.BidRequestAuditHistory;
import com.fizzkai.p2p.bussness.domain.ExpAccount;
import com.fizzkai.p2p.bussness.domain.PaymentSchedule;
import com.fizzkai.p2p.bussness.domain.PaymentScheduleDetail;
import com.fizzkai.p2p.bussness.domain.SystemAccount;
import com.fizzkai.p2p.bussness.mapper.BidRequestMapper;
import com.fizzkai.p2p.bussness.query.BidRequestQuery;
import com.fizzkai.p2p.bussness.service.IAccountFlowService;
import com.fizzkai.p2p.bussness.service.IBidRequestAuditHistoryService;
import com.fizzkai.p2p.bussness.service.IBidRequestService;
import com.fizzkai.p2p.bussness.service.IBidService;
import com.fizzkai.p2p.bussness.service.IExpAccountFlowService;
import com.fizzkai.p2p.bussness.service.IExpAccountService;
import com.fizzkai.p2p.bussness.service.IPaymentScheduleDetailService;
import com.fizzkai.p2p.bussness.service.IPaymentScheduleService;
import com.fizzkai.p2p.bussness.service.ISystemAccountFlowService;
import com.fizzkai.p2p.bussness.service.ISystemAccountService;
import com.fizzkai.p2p.bussness.util.CalculatetUtil;
import com.fizzkai.p2p.core.domain.Account;
import com.fizzkai.p2p.core.domain.BaseAuthDomain;
import com.fizzkai.p2p.core.domain.UserInfo;
import com.fizzkai.p2p.core.exception.DisplayableException;
import com.fizzkai.p2p.core.query.QueryObject;
import com.fizzkai.p2p.core.service.IAccountService;
import com.fizzkai.p2p.core.service.IUserInfoService;
import com.fizzkai.p2p.core.util.AssertUtil;
import com.fizzkai.p2p.core.util.BitStateUtil;
import com.fizzkai.p2p.core.util.Constants;
import com.fizzkai.p2p.core.util.UserContext;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service@Transactional
public class BidRequestServiceImpl implements IBidRequestService {

    @Autowired
    private BidRequestMapper bidRequestMapper;
    @Autowired
    private IUserInfoService userInfoService;
    @Autowired
    private IAccountService accountService;
    @Autowired
    private IExpAccountService expAccountService;
    @Autowired
    private IAccountFlowService accountFlowService;
    @Autowired
    private IExpAccountFlowService expAccountFlowService;
    @Autowired
    private IBidRequestAuditHistoryService auditHistoryService;
    @Autowired
    private IBidService bidService;
    @Autowired
    private ISystemAccountService systemAccountService;
    @Autowired
    private ISystemAccountFlowService systemAccountFlowService;
    @Autowired
    private IPaymentScheduleService paymentScheduleService;
    @Autowired
    private IPaymentScheduleDetailService paymentScheduleDetailService;

    @Override
    public int save(BidRequest entity) {
        return bidRequestMapper.insert(entity);
    }

    @Override
    public int update(BidRequest entity) {
        int row = bidRequestMapper.updateByPrimaryKey(entity);
        AssertUtil.updateNotZero(row);
        return row;
    }

    @Override
    public BidRequest get(Long id) {
        return bidRequestMapper.selectByPrimaryKey(id);
    }

    @Override
    public PageInfo<BidRequest> query(QueryObject qo) {
        PageHelper.startPage(qo.getPageNum(), qo.getPageSize());
        List<BidRequest> list = bidRequestMapper.queryList(qo);
        return new PageInfo<>(list);
    }

    @Override
    public void apply(BidRequest br) {
        // 用户 不能借款
        UserInfo userInfo = userInfoService.getCurrent();
        Account account = accountService.getCurrent();
        if (!userInfo.isCanBorrow()     // 没有认证
            || userInfo.isHasBidRequestProcess()  // 正在借款中
            || br.getBidRequestAmount().compareTo(Constants.BORROW_AMOUNT_MIN) < 0   // 借款金额 < 最小值
            || br.getBidRequestAmount().compareTo(account.getRemainBorrowLimit()) > 0 // 借款金额 > 可借金额
            || br.getMinBidAmount().compareTo(Constants.BID_AMOUNT_MIN) < 0 //  设置投标金额 < 最小投标金额
            || br.getCurrentRate().compareTo(Constants.CURRENT_RATE_MIN) < 0 // 利息 < 最小利息
            || br.getCurrentRate().compareTo(Constants.CURRENT_RATE_MAX) > 0 // 利息 > 利息
            ) {
            throw new DisplayableException("非法操作");
        }

        // 设置 部分 前台内容
        BidRequest req = new BidRequest();
        req.setTitle(br.getTitle());
        req.setDescription(br.getDescription());

        req.setBidRequestAmount(br.getBidRequestAmount());  // 总额
        req.setCurrentRate(br.getCurrentRate());    // 利息
        req.setMonthes2Return(br.getMonthes2Return());  // 借款期限
        req.setMinBidAmount(br.getMinBidAmount());  // 最小投标金额
        req.setDisableDays(br.getDisableDays());    // 招标天数

        // 设置 后台内容
        req.setApplyTime(new Date());   // 申请时间
        req.setCreateUser(UserContext.getCurrentLoginInfo());   // 借款人
        req.setBidRequestState(Constants.BIDREQUEST_STATE_APPLY);   // 借款状态：申请中
        req.setBidRequestType(Constants.BIDREQUEST_TYPE_NORMAL);    // 借款类型 普通信用标

        // 设置 还款 类型
        if (br.getReturnType() == Constants.RETURN_TYPE_MONTH_INTEREST) {// 归还类型
            req.setReturnType(Constants.RETURN_TYPE_MONTH_INTEREST);  // 按月到期还款(每月还利息,到期还本息)

        } else {
            req.setReturnType(Constants.RETURN_TYPE_MONTH_INTEREST_PRINCIPAL);  // 按月分期还款(等额本息)
        }
        // 设置 借款 总利息
        BigDecimal totalRewardAmount = CalculatetUtil.calTotalInterest(req.getReturnType(), req.getBidRequestAmount(), req.getCurrentRate(), req.getMonthes2Return());
        req.setTotalRewardAmount(totalRewardAmount);
        // 保存 借款
        save(req);
        // 保存 用户
        userInfo.addState(BitStateUtil.HAS_BIDREQUEST_PROCESS);
        userInfoService.update(userInfo);
    }
    @Override
    public void applyExp(BidRequest br) {
        // 用户 不能借款
        if (br.getMinBidAmount().compareTo(Constants.BID_AMOUNT_MIN) < 0 //  设置投标金额 < 最小投标金额
            || br.getCurrentRate().compareTo(Constants.CURRENT_RATE_MIN) < 0 // 利息 < 最小利息
            || br.getCurrentRate().compareTo(Constants.CURRENT_RATE_MAX) > 0 // 利息 > 利息
            ) {
            throw new DisplayableException("非法操作");
        }
        // 设置 部分 前台内容
        BidRequest req = new BidRequest();
        req.setTitle(br.getTitle());
//        req.setDescription(br.getDescription());    // 描述，没有
        req.setBidRequestAmount(br.getBidRequestAmount());  // 总额
        req.setCurrentRate(br.getCurrentRate());    // 利息
        req.setMonthes2Return(br.getMonthes2Return());  // 借款期限
        req.setMinBidAmount(br.getMinBidAmount());  // 最小投标金额
        req.setDisableDays(br.getDisableDays());    // 招标天数
        // 设置 后台内容
        req.setApplyTime(new Date());   // 申请时间
        req.setCreateUser(UserContext.getCurrentLoginInfo());   // 借款人
        req.setBidRequestState(Constants.BIDREQUEST_STATE_APPLY);   // 借款状态：申请中
        req.setBidRequestType(Constants.BIDREQUEST_TYPE_EXP);    // 借款类型 体验·标
        // 设置 还款 类型
        if (br.getReturnType() == Constants.RETURN_TYPE_MONTH_INTEREST) {// 归还类型
            req.setReturnType(Constants.RETURN_TYPE_MONTH_INTEREST);  // 按月到期还款(每月还利息,到期还本息)
        } else {
            req.setReturnType(Constants.RETURN_TYPE_MONTH_INTEREST_PRINCIPAL);  // 按月分期还款(等额本息)
        }
        // 设置 借款 总利息
        BigDecimal totalRewardAmount = CalculatetUtil.calTotalInterest(req.getReturnType(), req.getBidRequestAmount(), req.getCurrentRate(), req.getMonthes2Return());
        req.setTotalRewardAmount(totalRewardAmount);
        // 保存 借款
        save(req);
    }


    @Override
    public void publishAudit(Long id, Integer state, Date publishTime, String remark) {
        BidRequest bidRequest = bidRequestMapper.selectByPrimaryKey(id);
        // 杜绝状态
        if (bidRequest == null  // 状态不对
            || Constants.BIDREQUEST_STATE_APPLY != bidRequest.getBidRequestState() ) {
            throw new DisplayableException("非法参数");
        }
        // 记录 审核历史 保存 审核历史
        auditHistoryService.createHistory(bidRequest, state, remark, BidRequestAuditHistory.TYPE_PUBLISH);
        // 开始 审核
        if (state.equals(BaseAuthDomain.STATE_PASS)) {
            // 通过
            publishAuditPass(publishTime, bidRequest);
        } else {
            // 拒绝
            publishAuditRefuse(bidRequest);
        }
        // 设置 风控意见
        bidRequest.setNote(remark);
        // 更新 借款对象
        update(bidRequest);
    }
    // 发标前审核 不通过
    private void publishAuditRefuse(BidRequest bidRequest) {
        bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_PUBLISH_REFUSE);
        if (bidRequest.getBidRequestType() == Constants.BIDREQUEST_TYPE_NORMAL) {
            // 移除 UserInfo 借款 状态
            UserInfo createUser = userInfoService.get(bidRequest.getCreateUser().getId());
            createUser.removeState(BitStateUtil.HAS_BIDREQUEST_PROCESS);
            userInfoService.update(createUser);
        }
    }

    // 发标前审核 通过
    private void publishAuditPass(Date publishTime, BidRequest bidRequest) {
        if (publishTime == null) {
            // 立即发布
            bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_BIDDING);
            bidRequest.setPublishTime(new Date());  // 时间
        } else {
            // 定时发布
            bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_PUBLISH_PENDING);
            bidRequest.setPublishTime(DateUtils.setMilliseconds(publishTime, 0));  // 时间
        }
        // 设置 招标停止 时间
        bidRequest.setDisableDate(DateUtils.addDays(bidRequest.getPublishTime(), bidRequest.getDisableDays()));
    }

    @Override
    public List<BidRequest> queryPublicPendingBidRequest() {
        BidRequestQuery qo = new BidRequestQuery();
        qo.setBidRequestState(Constants.BIDREQUEST_STATE_PUBLISH_PENDING);
        List<BidRequest> list = bidRequestMapper.queryList(qo);
        return list;
    }

    @Override
    public List<BidRequest> queryPublishPendingBidInOneHourRequest() {
        BidRequestQuery qo = new BidRequestQuery();
        qo.setBidRequestState(Constants.BIDREQUEST_STATE_PUBLISH_PENDING);  // 待发标
        qo.setEndTime(DateUtils.addHours(new Date (), 1)); // 一个小时之内
        return bidRequestMapper.queryList(qo);
    }

    @Override
    public List<BidRequest> queryNormalIndexData() {
        return queryIndexData(Constants.BIDREQUEST_TYPE_NORMAL);
    }


    @Override
    public List<BidRequest> queryExpIndexData() {
        return queryIndexData(Constants.BIDREQUEST_TYPE_EXP);
    }

    private List<BidRequest> queryIndexData(int bidRequestType) {
        BidRequestQuery qo = new BidRequestQuery();
        qo.setStates(new int[]{ Constants.BIDREQUEST_STATE_BIDDING, Constants.BIDREQUEST_STATE_PAYING_BACK, Constants.BIDREQUEST_STATE_COMPLETE_PAY_BACK});
        qo.setBidRequestType(bidRequestType);
        qo.setOrderByCondition("order by br.bidRequestState");
        PageHelper.startPage(1, 5);
        return bidRequestMapper.queryList(qo);
    }

    @Override
    public void bid(Long bidRequestId, BigDecimal amount) {
        BidRequest bidRequest = bidRequestMapper.selectByPrimaryKey(bidRequestId);
        // 杜绝 非法 参数
        if (bidRequest == null  // 借款 不存在
            || amount == null // 金额不存在
            || bidRequest.getBidRequestState() != Constants.BIDREQUEST_STATE_BIDDING // 借款状态 不符合
            || amount.compareTo(bidRequest.getRemainAmount()) > 0 // 投标大于 可投金额
            || amount.compareTo(Constants.BID_AMOUNT_MIN) < 0   // 投标 小于 最小投标金额
            ) {
            throw new DisplayableException("非法参数");
        }
        if (bidRequest.getBidRequestType() == Constants.BIDREQUEST_TYPE_NORMAL) {
            inner_bidNormal(amount, bidRequest);
        } else {
            inner_bidExp(amount, bidRequest);
        }
        // 更新 借款对象
        this.update(bidRequest);
    }

    private void inner_bidExp(BigDecimal amount, BidRequest bidRequest) {
        // 获取 当前 用户 余额
        ExpAccount account = expAccountService.get(UserContext.getCurrentLoginInfo().getId());
        if (amount.compareTo(account.getUsableAmount()) > 0 ) {    // 投标大于 余额
            throw new DisplayableException("非法参数");
        }
        // 投标
        // 设置 前台的 参数
        Bid bid = new Bid();
        bid.setAvailableAmount(amount);
        // 设置后台的 参数
        bid.setBidRequestId(bidRequest.getId());
        bid.setActualRate(bidRequest.getCurrentRate());
        bid.setBidRequestTitle(bidRequest.getTitle());
        bid.setBidRequestState(bidRequest.getBidRequestState());
        bid.setBidUser(UserContext.getCurrentLoginInfo());
        bid.setBidTime(new Date());
        bidService.save(bid);
        // 保存 投标对象


        // 对于投资人
        account.setUsableAmount(account.getUsableAmount().subtract(amount));    // 修改 可用余额
        account.setFreezedAmount(account.getFreezedAmount().add(amount));       // 修改 冻结资金
        expAccountService.update(account);// 更新投资

        // 对于 借款 对象
        // 修改 借款对象的 属性
        bidRequest.setBidCount(bidRequest.getBidCount() + 1);   // 合计投标个数
        bidRequest.setCurrentSum(bidRequest.getCurrentSum().add(amount));   // 添加 投标金额
        // 判断 是否满标
        if (bidRequest.getBidRequestAmount().compareTo(bidRequest.getCurrentSum()) == 0) {
            // 满标, 修改状态
            bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_APPROVE_PENDING_2);    // 设置为 满标二审
            // 给子标 设置状态
            bidService.updateState(bidRequest.getId(), Constants.BIDREQUEST_STATE_APPROVE_PENDING_2);
        }
    }

    private void inner_bidNormal(BigDecimal amount, BidRequest bidRequest) {
        // 获取 当前 用户 余额
        Account account = accountService.get(UserContext.getCurrentLoginInfo().getId());
        if (amount.compareTo(account.getUsableAmount()) > 0      // 投标大于 余额
            ) {
            throw new DisplayableException("非法参数");
        }
        // 投标
        // 设置 前台的 参数
        Bid bid = new Bid();
        bid.setAvailableAmount(amount);
        // 设置后台的 参数
        bid.setBidRequestId(bidRequest.getId());
        bid.setActualRate(bidRequest.getCurrentRate());
        bid.setBidRequestTitle(bidRequest.getTitle());
        bid.setBidRequestState(bidRequest.getBidRequestState());
        bid.setBidUser(UserContext.getCurrentLoginInfo());
        bid.setBidTime(new Date());
        bidService.save(bid);
        // 保存 投标对象


        // 对于投资人
        account.setUsableAmount(account.getUsableAmount().subtract(amount));    // 修改 可用余额
        account.setFreezedAmount(account.getFreezedAmount().add(amount));       // 修改 冻结资金
        accountService.update(account);// 更新投资

        // 对于 借款 对象
        // 修改 借款对象的 属性
        bidRequest.setBidCount(bidRequest.getBidCount() + 1);   // 合计投标个数
        bidRequest.setCurrentSum(bidRequest.getCurrentSum().add(amount));   // 添加 投标金额
        // 判断 是否满标
        if (bidRequest.getBidRequestAmount().compareTo(bidRequest.getCurrentSum()) == 0) {
            // 满标, 修改状态
            bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_APPROVE_PENDING_1);    // 设置为 满标一审
            // 给子标 设置状态
            bidService.updateState(bidRequest.getId(), Constants.BIDREQUEST_STATE_APPROVE_PENDING_1);
        }
    }

    @Override
    public void audit1(Long bidRequestId, Integer state, String remark) {
        // 杜绝状态
        BidRequest bidRequest = get(bidRequestId);
        if (bidRequest == null  //  借款不存在
            || state == null // 无状态
            || bidRequest.getBidRequestState() != Constants.BIDREQUEST_STATE_APPROVE_PENDING_1 // 状态 不匹配
            ) {
            throw new DisplayableException("非法参数");
        }
        // 审核流水
        // 前台设置 state / remark
        auditHistoryService.createHistory(bidRequest, state, remark, BidRequestAuditHistory.TYPE_AUDIT_1);
        if (state == BidRequestAuditHistory.STATE_PASS) {
            // 审核 通过
            // 修改 bidRequest 状态，满标 2审
            bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_APPROVE_PENDING_2);
            // 修改 bid 状态
            bidService.updateState(bidRequest.getId(), Constants.BIDREQUEST_STATE_APPROVE_PENDING_2);
        } else {
            // 审核 拒绝
            auditReject(bidRequest, remark);

        }
        // 后台 添加内容
        this.update(bidRequest);
    }

    /**
     * 满审 拒绝方法 抽取
     * @param bidRequest 被拒绝的 id
     * @param remark 备注
     */
    private void auditReject(BidRequest bidRequest, String remark) {
        // 修改 bid 和， bidRequest状态
        bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_REJECTED);
        bidService.updateState(bidRequest.getId(), Constants.BIDREQUEST_STATE_REJECTED);
        if (bidRequest.getBidRequestType() == Constants.BIDREQUEST_TYPE_NORMAL) {
            auditRejectNormal(bidRequest, remark);
        } else {
            auditRejectExp(bidRequest, remark);
        }
        // 保存 借款 对象
        this.update(bidRequest);
    }

    private void auditRejectExp(BidRequest bidRequest, String remark) {
        // 对于 投标人
        List<Bid> bids = bidRequest.getBids();
        // 创建 map 接受
        HashMap<Long, ExpAccount> map = new HashMap<>();
        // 遍历· 投标人
        Long bidUserId;
        ExpAccount account;
        for (Bid bid : bids) {
            bidUserId = bid.getBidUser().getId();
            account = map.get(bidUserId);
            // account 不存在, 设置进去
            if (account == null) {
                account = expAccountService.get(bidUserId);
                map.put(bidUserId, account);
            }
            // account 合计金额
            account.setUsableAmount(account.getUsableAmount().add(bid.getAvailableAmount()));
            account.setFreezedAmount(account.getFreezedAmount().subtract(bid.getAvailableAmount()));
            // 记录流水
            expAccountFlowService.createAuditFailFlow(account, bid.getAvailableAmount(), remark);
        }
        // 给投标人 更新 account
        for (ExpAccount account1 : map.values()) {
            expAccountService.update(account1);
        }
    }

    private void auditRejectNormal(BidRequest bidRequest, String remark) {
        // 对于 借款人 移除借款状态
        UserInfo createUser = userInfoService.get(bidRequest.getCreateUser().getId());
        createUser.removeState(BitStateUtil.HAS_BIDREQUEST_PROCESS);    // 移除借款状态
        userInfoService.update(createUser);     // 更新
        // 对于 投标人
        List<Bid> bids = bidRequest.getBids();
        // 创建 map 接受
        HashMap<Long, Account> map = new HashMap<>();
        // 遍历· 投标人
        Long bidUserId;
        Account account;
        for (Bid bid : bids) {
            bidUserId = bid.getBidUser().getId();
            account = map.get(bidUserId);
            // account 不存在, 设置进去
            if (account == null) {
                account = accountService.get(bidUserId);
                map.put(bidUserId, account);
            }
            // account 合计金额
            account.setUsableAmount(account.getUsableAmount().add(bid.getAvailableAmount()));
            account.setFreezedAmount(account.getFreezedAmount().subtract(bid.getAvailableAmount()));
            // 记录流水
            accountFlowService.createAuditFailFlow(account, bid.getAvailableAmount(), remark);
        }
        // 给投标人 更新 account
        for (Account account1 : map.values()) {
            accountService.update(account1);
        }
    }

    @Override
    public void audit2(Long id, Integer state, String remark) {
        // 1. 判断 条件
        BidRequest bidRequest = this.get(id);
        if (bidRequest == null  // id 不存在
            || bidRequest.getBidRequestState() != Constants.BIDREQUEST_STATE_APPROVE_PENDING_2 // 状态 不是二审
            ) {
            throw new DisplayableException("非法操作");
        }
        // 1.88 创建 审核历史
        auditHistoryService.createHistory(bidRequest, state, remark, BidRequestAuditHistory.TYPE_AUDIT_2);
        if (!state.equals(BaseAuthDomain.STATE_PASS)) {
            // 审核 失败, 跟 audit1 一样
            auditReject(bidRequest, remark);
            return;
        }
        // 审核 通过
        // 2. 对于 借款对象 修改状态 还款中
        bidRequest.setBidRequestState(Constants.BIDREQUEST_STATE_PAYING_BACK);
        // 3. 投标对象 修改状态 还款中
        bidService.updateState(bidRequest.getId(), Constants.BIDREQUEST_STATE_PAYING_BACK);

        if (bidRequest.getBidRequestType() == Constants.BIDREQUEST_TYPE_NORMAL) {
            inner_audit2PassNormal(remark, bidRequest);
        } else {
            inner_audit2PassExp(remark, bidRequest);
        }
        // 保存 借款 对象
        this.update(bidRequest);
    }

    private void inner_audit2PassExp(String remark, BidRequest bidRequest) {

        // 6. 投标人
        // 抽取 map 优化
        Map<Long, Account> accountMap = new HashMap<>();
        Map<Long, ExpAccount> bidAccountMap = new HashMap<>();
        Long bidUserId;
        ExpAccount bidAccount;
        // 抽取 利息
        BigDecimal interestTemp = Constants.ZERO;
        // 获取 利息
        BigDecimal money;

        // 6.1 投标人的 账户 修改金额
        List<Bid> bids = bidRequest.getBids();
        for (int index = 0; index < bids.size(); index++) {
            Bid bid = bids.get(index);
            bidUserId = bid.getBidUser().getId();
            bidAccount = bidAccountMap.get(bidUserId);
            if (bidAccount == null) {
                bidAccount = expAccountService.get(bidUserId);
                bidAccountMap.put(bidUserId, bidAccount);
                accountMap.put(bidUserId, accountService.get(bidUserId));
            }

            // 修改 金额
            // 修改冻结资金
            bidAccount.setFreezedAmount(bidAccount.getFreezedAmount().subtract(bid.getAvailableAmount()));
            // 修改 待收本金
//            bidAccount.setUnReceivePrincipal(bidAccount.getUnReceivePrincipal().add(bid.getAvailableAmount()));
            // 创建利息 TODO，还款对象 + 明细对象 生成之后
            // 记录流水, 流水值记录 可以金额，和 冻结金额，所以 利息可以 后面再算
            expAccountFlowService.createBidSuccessFlow(bidAccount, bid.getAvailableAmount(), remark);
        }

        // 7. 生成 还款对象 + 还款明细对象
        List<PaymentSchedule> list = createPaymentSchedules(bidRequest);

        Account accountTemp;
        for (PaymentSchedule ps : list) {
            for (PaymentScheduleDetail psd : ps.getDetails()) {
                accountTemp = accountMap.get(psd.getInvestorId());
                accountTemp.setUnReceiveInterest(accountTemp.getUnReceiveInterest().add(psd.getInterest()));
            }
        }
        // 更新 投标人的 account
        for (ExpAccount account : bidAccountMap.values()) {
            expAccountService.update(account);
        }
        for (Account account : accountMap.values()) {
            accountService.update(account);
        }
    }

    private void inner_audit2PassNormal(String remark, BidRequest bidRequest) {
        // 4. 借款人
        // 4.1 获取 借款人 账户
        Long createUserId = bidRequest.getCreateUser().getId();
        Account requestAccount = accountService.get(createUserId);
        // 4.2 给借款人 添加 money, 待还 金额
        requestAccount.setUsableAmount(requestAccount.getUsableAmount().add(bidRequest.getBidRequestAmount()));
        requestAccount.setUnReturnAmount(requestAccount.getUnReturnAmount().add(bidRequest.getTotalRewardAmount()).add(bidRequest.getBidRequestAmount()));
        // 4.3 减少授信额度
        requestAccount.setRemainBorrowLimit(requestAccount.getRemainBorrowLimit().subtract(bidRequest.getBidRequestAmount()));
        // 4.4 借款 流水
        accountFlowService.createBorrowSuccessFlow(requestAccount, bidRequest.getBidRequestAmount(), remark);
        // 4.5 扣除手续费
        BigDecimal managementCharge = CalculatetUtil.calAccountManagementCharge(bidRequest.getBidRequestAmount());
        requestAccount.setUsableAmount(requestAccount.getUsableAmount().subtract(managementCharge));
        // 4.6 生成流水
        accountFlowService.createAccountManagementChargeFlow(requestAccount, managementCharge, remark);
        // 4.7 更新账户
        accountService.update(requestAccount);
        // 4.8 借款人 状态 改变， 移除借款 状态
        UserInfo createUser = userInfoService.get(createUserId);
        createUser.removeState(BitStateUtil.HAS_BIDREQUEST_PROCESS);
        userInfoService.update(createUser);

        // 5. 系统账户
        SystemAccount systemAccount = systemAccountService.getCurrent();
        // 5.1 系统添加 money
        systemAccount.setUsableAmount(systemAccount.getUsableAmount().add(managementCharge));
        systemAccountService.update(systemAccount);
        // 5.2 生成 收取用户 借款手续费的 ，流水
        systemAccountFlowService.createGainAccountManagementChargeFlow(systemAccount, managementCharge);

        // 6. 投标人

        // 抽取 map 优化
        Map<Long, Account> bidAccountMap = new HashMap<>();
        Long bidUserId;
        Account bidAccount;
        // 抽取 利息
        BigDecimal interestTemp = Constants.ZERO;
        // 获取 利息
        BigDecimal money;

        // 6.1 投标人的 账户 修改金额
        List<Bid> bids = bidRequest.getBids();
        for (int index = 0; index < bids.size(); index++) {
            Bid bid = bids.get(index);
            bidUserId = bid.getBidUser().getId();
            bidAccount = bidAccountMap.get(bidUserId);
            if (bidAccount == null) {
                bidAccount = accountService.get(bidUserId);
                bidAccountMap.put(bidUserId, bidAccount);
            }

            // 修改 金额
            // 修改冻结资金
            bidAccount.setFreezedAmount(bidAccount.getFreezedAmount().subtract(bid.getAvailableAmount()));
            // 修改 待收本金
//            bidAccount.setUnReceivePrincipal(bidAccount.getUnReceivePrincipal().add(bid.getAvailableAmount()));
            // 创建利息 TODO，还款对象 + 明细对象 生成之后
            // 记录流水, 流水值记录 可以金额，和 冻结金额，所以 利息可以 后面再算
            accountFlowService.createBidSuccessFlow(bidAccount, bid.getAvailableAmount(), remark);
        }

        // 7. 生成 还款对象 + 还款明细对象
        List<PaymentSchedule> list = createPaymentSchedules(bidRequest);

        Account accountTemp;
        for (PaymentSchedule ps : list) {
            for (PaymentScheduleDetail psd : ps.getDetails()) {
                accountTemp = bidAccountMap.get(psd.getInvestorId());
                accountTemp.setUnReceiveInterest(accountTemp.getUnReceiveInterest().add(psd.getInterest()));
                accountTemp.setUnReceivePrincipal(accountTemp.getUnReceivePrincipal().add(psd.getPrincipal()));
            }
        }

        // 更新 投标人的 account
        for (Account account : bidAccountMap.values()) {
            accountService.update(account);
        }
    }


    // 根据 借款对象 创建 还款对象
    private List<PaymentSchedule> createPaymentSchedules(BidRequest bidRequest) {
        // 创建返回值
        ArrayList<PaymentSchedule> list = new ArrayList<>();

        // 抽取定义变量
        PaymentSchedule ps;
        BigDecimal amount;
        BigDecimal interest;
        // 定义 容器 中间值
        BigDecimal interestTemp = Constants.ZERO;
        BigDecimal amountTemp = Constants.ZERO;

        // 遍历月份
        int months = bidRequest.getMonthes2Return();
        for (int index = 0; index < months; index++) {
            ps = new PaymentSchedule();
            // 借款对象 参数设置
            ps.setBidRequestId(bidRequest.getId());
            ps.setBorrowUser(bidRequest.getCreateUser());
            ps.setBidRequestTitle(bidRequest.getTitle());
            ps.setBidRequestType(bidRequest.getBidRequestType());
            ps.setReturnType(bidRequest.getReturnType());
            // 第几期限
            ps.setMonthIndex(index + 1);
            ps.setDeadLine(DateUtils.addMonths(bidRequest.getPublishTime(), index + 1));

            if (index != months - 1) {
                // 不是最后 一期
                // 设置 每期还款
                amount = CalculatetUtil.calMonthToReturnMoney(bidRequest.getReturnType(), bidRequest.getBidRequestAmount(), bidRequest.getCurrentRate(), index + 1, bidRequest.getMonthes2Return());
                ps.setTotalAmount(amount);
                amountTemp = amountTemp.add(amount);
                // 设置 每期利息
                interest = CalculatetUtil.calMonthlyInterest(bidRequest.getReturnType(), bidRequest.getBidRequestAmount(), bidRequest.getCurrentRate(), index + 1, bidRequest.getMonthes2Return());
                interestTemp = interestTemp.add(interest);
                ps.setInterest(interest);
                // 设置 每期本金
                ps.setPrincipal(amount.subtract(interest));
            } else {
                // 是最后一期
                // 设置 每期还款
                ps.setTotalAmount(bidRequest.getBidRequestAmount().add(bidRequest.getTotalRewardAmount()).subtract(amountTemp));
                // 设置 每期利息
                ps.setInterest(bidRequest.getTotalRewardAmount().subtract(interestTemp));
                // 设置 每期本金
                ps.setPrincipal(ps.getTotalAmount().subtract(ps.getInterest()));
            }
            // 保存
            paymentScheduleService.save(ps);

            // 生成 Detail 对象
            createPaymentScheduleDetails(bidRequest, ps, list);

            // 添加进 list
            list.add(ps);
        }
        return list;
    }

    private void createPaymentScheduleDetails(BidRequest bidRequest, PaymentSchedule ps, ArrayList<PaymentSchedule> list) {
        // 创建设置对象
        ArrayList<PaymentScheduleDetail> resultList = new ArrayList<>();

        // 抽取变量 定义
        Bid bid;
        // 抽取 中间容器
        BigDecimal interestTemp = Constants.ZERO;
        BigDecimal totalAmountTemp = Constants.ZERO;
        // 遍历 投标对象
        List<Bid> bids = bidRequest.getBids();
        int size = bids.size();
        for (int index = 0; index < size; index++) {
            bid = bids.get(index);
            Long bidId = bid.getId();
            PaymentScheduleDetail psd = new PaymentScheduleDetail();
            // bidRequest 对象 参数
            psd.setBidRequestId(bidRequest.getId());
            psd.setBorrowUser(bidRequest.getCreateUser());
            psd.setReturnType(bidRequest.getReturnType());
            // bid 对象参数
            psd.setBidId(bidId);
            psd.setInvestorId(bid.getBidUser().getId());
            psd.setBidAmount(bid.getAvailableAmount());
            // ps 对象 参数
            psd.setPaymentScheduleId(ps.getId());
            psd.setMonthIndex(ps.getMonthIndex());
            psd.setDeadLine(ps.getDeadLine());
            // 计算属性
            if (bidRequest.getMonthes2Return() != ps.getMonthIndex() ||  ps.getMonthIndex() == 1) {
                // 不是最后一期
                if (index + 1 != size) {
                    // 不是 最后一个 bid
                    // 获取 比例
                    BigDecimal rate = bid.getAvailableAmount().divide(bidRequest.getBidRequestAmount(), Constants.SCALE_CAL, BigDecimal.ROUND_HALF_UP);
                    // 计算 monney
                    psd.setTotalAmount(ps.getTotalAmount().multiply(rate).setScale(Constants.SCALE_STORE, BigDecimal.ROUND_HALF_UP));
                    psd.setInterest(ps.getInterest().multiply(rate).setScale(Constants.SCALE_STORE, BigDecimal.ROUND_HALF_UP));
                    psd.setPrincipal(psd.getTotalAmount().subtract(psd.getInterest()));
                    interestTemp = interestTemp.add(psd.getInterest());
                    totalAmountTemp = totalAmountTemp.add(psd.getTotalAmount());
                } else {
                    // 是 最后一个 bid TODO
                    psd.setTotalAmount(ps.getTotalAmount().subtract(totalAmountTemp));
                    psd.setInterest(ps.getInterest().subtract(interestTemp));
                    psd.setPrincipal(psd.getTotalAmount().subtract(psd.getInterest()));
                }
            } else {
                // 是最后一期 TODO
                if (index + 1 != size) {
                    // 不是 最后一个 bid
                    // 获取 比例
                    BigDecimal rate = bid.getAvailableAmount().divide(bidRequest.getBidRequestAmount(), Constants.SCALE_CAL, BigDecimal.ROUND_HALF_UP);
                    // 计算 monney
                    BigDecimal val = list.stream()
                        .flatMap(item -> item.getDetails().stream())
                        .filter(item -> item.getBidId().equals(bidId))
                        .map(item -> item.getPrincipal()).reduce((oldVal, newVal) -> oldVal.add(newVal)).get();
                    psd.setTotalAmount(ps.getTotalAmount().multiply(rate).setScale(Constants.SCALE_STORE, BigDecimal.ROUND_HALF_UP));
                    psd.setPrincipal(bid.getAvailableAmount().subtract(val));
                    psd.setInterest(psd.getTotalAmount().subtract(psd.getPrincipal()));
                    interestTemp = interestTemp.add(psd.getInterest());
                    totalAmountTemp = totalAmountTemp.add(psd.getTotalAmount());
                } else {
                    // 是 最后一个 bid TODO
                    psd.setTotalAmount(ps.getTotalAmount().subtract(totalAmountTemp));
                    psd.setInterest(ps.getInterest().subtract(interestTemp));
                    psd.setPrincipal(psd.getTotalAmount().subtract(psd.getInterest()));
                }
            }
            paymentScheduleDetailService.save(psd);
            resultList.add(psd);
        }


        // 设置进 ps，用于 后面 给投标用户的 account 的 更新 利息
        ps.setDetails(resultList);
    }
}
